package cz.incad.psh.pshassign.server.search;

import cz.incad.psh.pshassign.server.Options;
import cz.incad.psh.pshassign.server.StopWords;
import java.io.InputStream;
import java.io.StringWriter;
import java.net.URLEncoder;
import java.util.ArrayList;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathFactory;
import org.apache.commons.io.IOUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

/**
 *
 * @author alberto
 */
public class PSHSearch1 implements Search {

    private String q;
    
    private double csPrefLabel;
    private double enPrefLabel;
    private double csAltLabel;
    private double enAltLabel;
    private double titleBoost;
    private double annotaceBoost;
    private double subjectBoost;
    private double konferenceBoost;
    XPathFactory factory = XPathFactory.newInstance();
    XPath xpath;
    XPathExpression expr;
    String xPathStr;
    DocumentBuilderFactory df = DocumentBuilderFactory.newInstance();
    ArrayList<String> stopWords;
    String action;
    String strength;

    @Override
    public String doSearch(String id) {
        try {
            
            strength = Options.getOption("assign", "strength");
            csPrefLabel = Options.getDouble("assign", "boost_csPrefLabel");
            enPrefLabel = Options.getDouble("assign", "boost_enPrefLabel");
            csAltLabel = Options.getDouble("assign", "boost_csAltLabel");
            enAltLabel = Options.getDouble("assign", "boost_enAltLabel");
            titleBoost = Options.getDouble("assign", "boost_title");
            annotaceBoost = Options.getDouble("assign", "boost_annotace");
            subjectBoost = Options.getDouble("assign", "boost_subjects");
            konferenceBoost = Options.getDouble("assign", "boost_konference");
            
            xpath = factory.newXPath();
        
        String urlStr = "http://localhost:8983/solr/nusl/tvrh?q=id:" + id;
        java.net.URL url = new java.net.URL(urlStr);

        df.setNamespaceAware(false);
        DocumentBuilder builder = df.newDocumentBuilder();

        InputStream is;
        is = url.openStream();
        Document dom = builder.parse(is);

        xPathStr = "response/result/doc/str[@name='source']";
        expr = xpath.compile(xPathStr);
        String source = (String) expr.evaluate(dom, XPathConstants.STRING);


//        xPathStr = "response/result/doc/str[@name='id']";
//        expr = xpath.compile(xPathStr);
//        String id = (String) expr.evaluate(dom, XPathConstants.STRING);


        xPathStr = "response/result/doc/str[@name='title']";
        expr = xpath.compile(xPathStr);
        String title = (String) expr.evaluate(dom, XPathConstants.STRING);
        title = title.trim().replace("\u00A0", " ")
                .replaceAll("\\)", "").replaceAll("\\(", "")
                .replaceAll("[:\\.\\,\\^]", "").trim();

        xPathStr = "response/result/doc/str[@name='annotace']";
        expr = xpath.compile(xPathStr);
        String annotace = (String) expr.evaluate(dom, XPathConstants.STRING);
        annotace = annotace.trim().replace("\u00A0", "")
                .replaceAll("\\)", "").replaceAll("\\(", "")
                .replaceAll("[:\\.\\,\\^]", "").trim();
        String sourceLink;
        if (source == null) {
            sourceLink = "http://invenio.nusl.cz/record/" + id;
        } else if (source.equals("aleph ntk")) {
            sourceLink = "http://aleph.techlib.cz/F/?func=direct&current_base=&format=999&doc_number=" + id;
        } else if (source.equals("invenio")) {
            sourceLink = "http://invenio.nusl.cz/record/" + id;
        } else {
            sourceLink = "http://invenio.nusl.cz/record/" + id;
        }
        String value;

        xPathStr = "response/result/doc/arr[@name='subject']/str";
        expr = xpath.compile(xPathStr);
        NodeList nodes = (NodeList) expr.evaluate(dom, XPathConstants.NODESET);
        int numberOfSubjects = nodes.getLength();
        String subjects = "";
        for (int i = 0; i < nodes.getLength(); i++) {
            Node node = nodes.item(i);
            if (node != null && node.hasChildNodes()) {
                if(node.getFirstChild().getNodeValue().toLowerCase().length()>0){
                    subjects += "(" + node.getFirstChild().getNodeValue().toLowerCase() + ") ";
                }
            }
        }
        
        subjects = subjects.trim();

        xPathStr = "response/result/doc/arr[@name='konference']/str";
        expr = xpath.compile(xPathStr);
        nodes = (NodeList) expr.evaluate(dom, XPathConstants.NODESET);
        String konferences = "";
        for (int i = 0; i < nodes.getLength(); i++) {
            Node node = nodes.item(i);
            if (node != null && node.hasChildNodes()) {
                konferences += node.getFirstChild().getNodeValue().toLowerCase() + " ";
            }
        }
        
        konferences = konferences.trim();


        xPathStr = "response/lst[@name='termVectors']/lst/lst/lst";
        expr = xpath.compile(xPathStr);
        nodes = (NodeList) expr.evaluate(dom, XPathConstants.NODESET);
        String vectors = "";
        String qvectors = "";
        for (int i = 0; i < nodes.getLength(); i++) {
            Node node = nodes.item(i);
            value = node.getAttributes().getNamedItem("name").getNodeValue().toLowerCase();
            if (value.length() > 3) {
                vectors += value + " (" + node.getParentNode().getAttributes().getNamedItem("name").getNodeValue() + "), ";
                qvectors += value + " ";
            }
        }

        xPathStr = "response/lst[@name='termVectors']/lst/lst[@name='title_vectors']/lst";
        expr = xpath.compile(xPathStr);
        nodes = (NodeList) expr.evaluate(dom, XPathConstants.NODESET);
        String qTitles = "";
        for (int i = 0; i < nodes.getLength(); i++) {
            Node node = nodes.item(i);
            value = node.getAttributes().getNamedItem("name").getNodeValue().toLowerCase().replaceAll("[:\\.\\,\\^]", "");
            if (value.length() > 3) {
                qTitles += " (" + value + ")^" + (titleBoost * 4);
                qTitles += " (csPrefLabel:" + value + ")^" + (titleBoost * 10);
            }
        }

        xPathStr = "response/lst[@name='termVectors']/lst/lst[@name='subject_vectors']/lst";
        expr = xpath.compile(xPathStr);
        nodes = (NodeList) expr.evaluate(dom, XPathConstants.NODESET);
        String qSubject = "";
        for (int i = 0; i < nodes.getLength(); i++) {
            Node node = nodes.item(i);
            value = node.getAttributes().getNamedItem("name").getNodeValue();
            if (value.length() > 3) {
                qSubject += "csPrefLabel:\"" + value.toLowerCase() + "\"^" + subjectBoost + " ";
            }
        }


        xPathStr = "response/lst[@name='termVectors']/lst/lst[@name='annotace_vectors']/lst";
        expr = xpath.compile(xPathStr);
        nodes = (NodeList) expr.evaluate(dom, XPathConstants.NODESET);
        String qAnnotace = "";
        for (int i = 0; i < nodes.getLength(); i++) {
            Node node = nodes.item(i);
            value = node.getAttributes().getNamedItem("name").getNodeValue();
            if (value.length() > 3) {
                qAnnotace += "csPrefLabel:\"" + value.toLowerCase() + "\" ";
            }
        }

        String qf = "_text _text_en csPrefLabel^" + (csPrefLabel * 8)
                + " enPrefLabel^" + enPrefLabel
                + " csAltLabel^" + csAltLabel
                + " enAltLabel^" + enAltLabel;

        String hl = "&hl=true&hl.fl=csPrefLabel_hl,enPrefLabel_hl,csAltLabel_hl,enAltLabel_hl"
                + "&hl.simple.pre=<b>&hl.simple.post=</b>"
                + "&hl.mergeContiguous=true&hl.snippets=5&hl.fragsize=0";
        
        String fl = "score,*";

        String finalQuery = "";
        String boostQuery = "";
        if (title.length() > 0) {
            boostQuery += " (" + title + ")^" + titleBoost;
            boostQuery += " (\"" + title + "\")^" + titleBoost;
            boostQuery += " csPrefLabel:(" + title + ")^" + titleBoost;
            boostQuery += qTitles;
            finalQuery += " " + title.trim();
        }
        if (subjects.length() > 0) {
            boostQuery += " " + subjects + "^" + subjectBoost;
            finalQuery += " " + subjects + subjects
                    .replaceAll("\\(", "\\(\"")
                    .replaceAll("\\)", "\"\\)");
        }
        if (annotace.length() > 0 && numberOfSubjects<3) {
            boostQuery += " (" + annotace.toLowerCase() + ")^" + annotaceBoost;
            finalQuery += " " + annotace.toLowerCase();
        }
        if (konferences.length() > 0) {
            boostQuery += " (" + konferences.toLowerCase() + ")^" + konferenceBoost;
            finalQuery += " " + konferences.toLowerCase();
        }
        //logger.log(Level.INFO, finalQuery);
        finalQuery = cleanQuery(finalQuery);
        boostQuery = cleanQuery(boostQuery);
        //logger.log(Level.INFO, finalQuery);

        urlStr = "http://localhost:8983/solr/PSH/select?wt=json&fl="+fl+"&rows=100"
                + "&defType=edismax&q.op=OR"
                + "&qf=" + URLEncoder.encode(qf, "UTF-8")
               //+ "&pf=" + URLEncoder.encode(qf, "UTF-8")
                + "&pf=" + URLEncoder.encode(boostQuery, "UTF-8")
                + hl
                + //"&q=" + URLEncoder.encode(qTitles + qAnnotace + qSubject, "UTF-8");
                //"&q=" + URLEncoder.encode(qvectors + qSubject, "UTF-8");
                "&q=" + URLEncoder.encode(finalQuery, "UTF-8");
        //"&q=(" + URLEncoder.encode(title, "UTF-8") + ")%5E"+titleBoost;
        //"&q=" + finalQuery;
        
            System.out.println(urlStr);
        url = new java.net.URL(urlStr);

        is = url.openStream();
        StringWriter writer = new StringWriter();
            IOUtils.copy(is, writer, "UTF-8");
            return writer.toString();
            
        } catch (Exception e) {
            System.out.println("error :\n" + e);
            e.printStackTrace();
            return "error " + e;
        }
    }

    private String cleanQuery(String old) throws Exception {
        String s = old;
//        for (String word : stopWords) {
//            s = s.replaceAll("\\b"+word+"\\b", "");
//        }
        s = StopWords.removeStopWords(s);
        s = s.replaceAll("\\(\\)\\^\\d\\s", "");
        s = s.replaceAll("\\(\\)\\^\\d.\\d\\s", "");
        s = s.replaceAll("\\?", "");
        s = s.replaceAll("~", "");
        s = s.replaceAll("  ", " ")
            .replaceAll("\\(\\)", "")
            .replaceAll("\\-", " ")
            .replaceAll("\\/", " ")
            .replaceAll("\\\\", "")
            .replaceAll("\\{", "")
            .replaceAll("\\}", "");
        
        s = s.replaceAll("/[^A-Za-z0-9 ]/", "");
        
        if(s.length()>1500){
            s = s.substring(0, 1500);
            s = s.substring(0, s.lastIndexOf(" "));
        }
        
        return s;
    }

}
